import logging
import os
import sys
import tkinter as tk
import cchardet
from pathlib import Path
from tkinter import Frame, Canvas, Scrollbar, ttk
from typing import Tuple
from typing import Optional, Dict, Any
from tkinter.ttk import Combobox


# 配置日志（在程序初始化时调用）
def setup_logging() -> None:
    """
    配置多级别日志分离到不同文件
    """
    log_dir = Path.cwd() / "log"
    log_dir.mkdir(exist_ok=True)  # 确保日志目录存在
    
    # 定义日志级别与格式
    levels = {
        logging.DEBUG: "DEBUG",
        logging.INFO: "INFO",
        logging.WARNING: "WARNING",
        logging.ERROR: "ERROR",
        logging.CRITICAL: "CRITICAL"
    }
    
    formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(filename)s:%(lineno)d - %(message)s")
    
    # 清除现有处理器（避免重复）
    root_logger = logging.getLogger()
    for handler in root_logger.handlers[:]:
        root_logger.removeHandler(handler)
    
    # 为每个级别创建独立文件处理器
    for level, level_name in levels.items():
        handler = logging.FileHandler(
            filename=str(log_dir / f"{level_name.lower()}.log"),
            encoding='utf-8'
        )
        handler.setLevel(level)
        handler.setFormatter(formatter)
        #handler.addFilter(lambda record: record.levelno == level)  # 精确级别过滤
        handler.addFilter(lambda record, lvl=level: record.levelno == lvl)

        root_logger.addHandler(handler)
    
    # 设置根记录器级别（必须设为最低级别）
    root_logger.setLevel(logging.DEBUG)


def resource_path(relative_path: str) -> str:
    """
    获取资源文件的绝对路径（兼容打包和开发环境）

    参数:
        relative_path (str): 相对路径，如 'pic/icon.png'

    返回:
        str: 绝对路径字符串
    """
    if hasattr(sys, '_MEIPASS'):
        # PyInstaller 打包后的临时目录
        base_path: Path = Path(sys._MEIPASS)  # type: ignore[attr-defined]
    else:
        # 普通开发环境，__file__ 所在目录
        base_path: Path = Path(__file__).parent

    return str(base_path / relative_path)


def create_innerframe_with_vsb(frame: Frame) -> Frame:
    """
    在指定frame内创建一个带垂直滚动条的canvas和嵌套frame, 返回内嵌frame对象
    """

    # 创建 Canvas 和 垂直滚动条
    canvas: Canvas = tk.Canvas(frame, borderwidth=0, background="#FFFFFF")
    vsb: Scrollbar = tk.Scrollbar(frame, orient="vertical", command=canvas.yview)
    canvas.configure(yscrollcommand=vsb.set)

    vsb.pack(side="right", fill="y")
    canvas.pack(side="left", fill="both", expand=True)

    # 创建内嵌 Frame
    inner_frame: Frame = tk.Frame(canvas, background="#FFFFFF")
    canvas.create_window((0, 0), window=inner_frame, anchor='nw')

    # 内容变化时更新滚动区域
    def on_frame_configure(event: tk.Event) -> None:
        canvas.configure(scrollregion=canvas.bbox("all"))
    inner_frame.bind("<Configure>", on_frame_configure)

    # 鼠标滚轮支持（局部绑定）
    def _on_mousewheel(event: tk.Event) -> None:
        canvas.yview_scroll(int(-1 * (event.delta / 120)), "units")
    canvas.bind("<Enter>", lambda e: canvas.bind_all("<MouseWheel>", _on_mousewheel))
    canvas.bind("<Leave>", lambda e: canvas.unbind_all("<MouseWheel>"))

    return inner_frame,vsb

def create_synced_scroll_canvases(
    frame1: Frame,
    frame2: Frame
) -> Tuple[Frame, Frame]:
    """
    在 frame1 和 frame2 中各创建一个带滚动条的 Canvas 并同步垂直滚动
    """

    # 两个 canvas 和 scrollbar
    canvas1 = Canvas(frame1, bg="#FFFFFF", borderwidth=0)
    scrollbar = Scrollbar(frame1, orient="vertical")
    canvas2 = Canvas(frame2, bg="#FFFFFF", borderwidth=0)

    # 配置canvas和scrollbar
    canvas1.configure(yscrollcommand=scrollbar.set)
    canvas2.configure(yscrollcommand=scrollbar.set)
    scrollbar.config(command=lambda *args: [canvas1.yview(*args), canvas2.yview(*args)])
        # 滚动条需要先放置，避免canvas扩张后无法放置滚动条
    scrollbar.pack(side="right", fill="y", expand=True)  
    canvas1.pack(side="left", fill="both", expand=True)
    canvas2.pack(fill="both", expand=True)
    
    
    # 嵌套 Frame 放入 canvas 中
    inner_frame_1 = Frame(canvas1, bg="#FFFFFF")
    inner_frame_2 = Frame(canvas2, bg="#FFFFFF")
    canvas1.create_window((0, 0), window=inner_frame_1, anchor="nw")
    canvas2.create_window((0, 0), window=inner_frame_2, anchor="nw")

    # 内容变化时更新 scrollregion
    def update_scrollregion(event):
        canvas1.configure(scrollregion=canvas1.bbox("all"))
        canvas2.configure(scrollregion=canvas2.bbox("all"))

    inner_frame_1.bind("<Configure>", update_scrollregion)
    inner_frame_2.bind("<Configure>", update_scrollregion)

    # 鼠标滚轮同步
    def on_mousewheel(event: tk.Event):
        delta = int(-1 * (event.delta / 120))
        canvas1.yview_scroll(delta, "units")
        canvas2.yview_scroll(delta, "units")

    def bind_mousewheel(canvas: Canvas):
        canvas.bind("<Enter>", lambda e: canvas.bind_all("<MouseWheel>", on_mousewheel))
        canvas.bind("<Leave>", lambda e: canvas.unbind_all("<MouseWheel>"))
        
    bind_mousewheel(canvas1)
    bind_mousewheel(canvas2)

    return inner_frame_1, inner_frame_2, scrollbar

def show_frame(frame:Frame) ->None:
    """
    输入frame提升到最上层显示
    """
    frame.tkraise()  

def detect_file_encoding(file_path: str) -> Optional[str]:
    """
    检测文件的编码格式
    """
    with open(file_path, 'rb') as f:
        raw_data: bytes = f.read()
        result: Dict[str, Any] = cchardet.detect(raw_data)  # 标注 result 的类型
        return result.get('encoding')
    
